package com.smsc.headend.task.engine.service.push.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.fwu.entity.DeviceFirmwareVersion;
import com.smsc.headend.module.fwu.entity.FirmwareFile;
import com.smsc.headend.module.fwu.entity.FirmwareFileVersion;
import com.smsc.headend.module.fwu.entity.LogFwUpgradeHis;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.push.entity.ConfigNotifyType;
import com.smsc.headend.module.push.entity.ConfigNotifyTypeParam;
import com.smsc.headend.module.scheme.entity.ConfigScheduleTask;
import com.smsc.headend.module.template.fwu.entity.TemplateFwUpgrade;
import com.smsc.headend.task.engine.mapper.*;
import com.smsc.headend.task.engine.po.DeviceDetail;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.DeviceFirmwareVersionService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.push.ConfigNotifyTypeParamService;
import com.smsc.headend.task.engine.service.push.PushDataDecodeHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * (业务实现)
 *
 * @author wjh
 * @date 2022/7/14 17:02.
 */
@Slf4j
public class UpgradeResultHandlerImpl implements PushDataDecodeHandler {

    private static final List<Long> meterUpgradeDataItemIdList = Arrays.asList(1100010040L);

    @Autowired
    ConfigNotifyTypeParamService paramService;
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    ConfigMeterTemplateMapper configMeterTemplateMapper;
    @Autowired
    LogFwUpgradeHisMapper logFwUpgradeHisMapper;
    @Autowired
    ConfigDcuTemplateMapper configDcuTemplateMapper;
    @Autowired
    DeviceFirmwareVersionService deviceFirmwareVersionService;
    @Autowired
    TemplateFwUpgradeMapper templateFwUpgradeMapper;
    @Autowired
    FirmwareFileMapper firmwareFileMapper;
    @Autowired
    FirmwareFileVersionMapper firmwareFileVersionMapper;
    @Autowired
    ConfigScheduleTaskMapper taskMapper;

    @Override
    public void handler(CosemData cosemData, ConfigNotifyType configNotifyType, DeviceDetail deviceDetail, Long dataItemId, Date uploadDate) {
        Long deviceId = deviceDetail.getDeviceId();
        Integer deviceType = deviceDetail.getDeviceTypeGroup().getDeviceType();
        Long modelId = deviceDetail.getDeviceTypeGroup().getModelId();

        uploadDate = null == uploadDate ? new Date() : uploadDate;
        List<ConfigNotifyTypeParam> params = paramService.getListByNotifyTypeId(configNotifyType.getNotifyTypeId());
        Map<String, ConfigNotifyTypeParam> paramMap = params
                .stream()
                .collect(Collectors.toMap(ConfigNotifyTypeParam::getParamName, e -> e));
        ConfigNotifyTypeParam childDataParam = paramMap.get("childData");
        ConfigNotifyTypeParam fileNameParam = paramMap.get("fileName");
        ConfigNotifyTypeParam fileTypeParam = paramMap.get("fileType");
        ConfigNotifyTypeParam statusParam = paramMap.get("status");
        ConfigNotifyTypeParam meterResultParam = paramMap.get("meterResultParam");
        if (null == childDataParam) {
            log.error("decode firmware upgrade result error,no param:childDataParam");
            return;
        }
        if (null == fileNameParam) {
            log.error("decode firmware upgrade result error,no param:fileNameParam");
            return;
        }
        if (null == fileTypeParam) {
            log.error("decode firmware upgrade result error,no param:fileTypeParam");
            return;
        }
        if (null == statusParam) {
            log.error("decode firmware upgrade result error,no param:statusParam");
            return;
        }
        CosemData childData = paramService.getCosemDataByIndex(cosemData, childDataParam.getParamIndex());
        if (null == childData) {
            log.error("decode dcu registry error,childData is null");
            return;
        }
        try {
            CosemData fileNameData = paramService.getCosemDataByIndex(childData, fileNameParam.getParamIndex());
            CosemData fileTypeData = paramService.getCosemDataByIndex(childData, fileTypeParam.getParamIndex());
            String fileName = Convert.toStr(cosemXmlService.getData(fileNameData.getType(), fileNameData.getValue()));
            String fileType = Convert.toStr(cosemXmlService.getData(fileTypeData.getType(), fileTypeData.getValue()));
            if (meterUpgradeDataItemIdList.contains(dataItemId)) {
                log.debug("decode meter firmware upgrade result");
                //从模块升级不处理，WI-SUN push从模块升级结果是在gateway将包传给主模块之后，至于从模块是否升级成功，gateway并不知晓
                if (null == meterResultParam) {
                    log.error("decode firmware upgrade result error,no param:meterResultParam");
                    return;
                }
                CosemData meterResults = paramService.getCosemDataByIndex(childData, meterResultParam.getParamIndex());
                List<CosemData> meterResultList = meterResults.getChild();
                ConfigNotifyTypeParam meterSnParam = paramMap.get("meterSn");
                if (null == meterSnParam) {
                    log.error("decode firmware upgrade result error,no param:meterSnParam");
                    return;
                }
                boolean containsMeterId = true;
                int status = -1;
                Long readversionTaskId = null;
                for (CosemData meterResult : meterResultList) {
                    CosemData meterSnData = paramService.getCosemDataByIndex(meterResult, meterSnParam.getParamIndex());
                    CosemData statusData = paramService.getCosemDataByIndex(meterResult, statusParam.getParamIndex());
                    String meterSn = Convert.toStr(cosemXmlService.getData(meterSnData.getType(), meterSnData.getValue()));
                    status = Convert.toInt(cosemXmlService.getData(statusData.getType(), statusData.getValue()));
                    if (StrUtil.isEmpty(meterSn)) {
                        //不包含meterSn，终止for循环
                        containsMeterId = false;
                        break;
                    }
                    Meter meter = assetManagementService.getMeterByMfgSn(meterSn);
                    if (null == meter) {
                        continue;
                    }
                    Long taskId = updateMeterFwUpgradeHisLog(meter.getMeterId(), fileName, fileType, status, DeviceType.METER.getId().intValue(), uploadDate, meter.getModelId());
                    if (taskId != null) {
                        readversionTaskId = taskId;
                    }
                }
                if (!containsMeterId) {
                    //不包含meterSn则更新最近的一批状态
                    updateMeterFwUpgradeHisLogByDcu(deviceId, fileName, uploadDate, status);
                } else {
                    if (null != readversionTaskId) {
                        assetManagementService.updateFwScheduleTaskLog(readversionTaskId, uploadDate.getTime() / 1000L);
                    }
                }
            } else {
                log.debug("decode gateway firmware upgrade result");
                CosemData statusData = paramService.getCosemDataByIndex(childData, statusParam.getParamIndex());
                int status = Convert.toInt(cosemXmlService.getData(statusData.getType(), statusData.getValue()));
                Long readVersionTaskId = updateDcuFwUpgradeHisLog(deviceId, fileName, fileType, status, deviceType, uploadDate, modelId);
                if (null != readVersionTaskId) {
                    assetManagementService.updateFwScheduleTaskLog(readVersionTaskId, uploadDate.getTime() / 1000L);
                }
            }
        } catch (Exception e) {
            log.error("decode firmware upgrade result Exception,{}", e.getMessage());
        }
    }

    public void updateMeterFwUpgradeHisLogByDcu(Long dcuId, String fileName, Date uploadDate, Integer status) {
        if (StrUtil.isEmpty(fileName)) {
            log.warn("decode firmware upgrade result warning,fileName is null");
            return;
        }
        List<FirmwareFile> firmwareFileList = firmwareFileMapper.getByFwFileName(fileName);
        if (CollectionUtils.isEmpty(firmwareFileList)) {
            log.warn("decode firmware upgrade result warning,firmwareFileList is empty");
            return;
        }
        List<Long> fileIdList = firmwareFileList.stream().map(FirmwareFile::getFwFileId).collect(Collectors.toList());
        List<TemplateFwUpgrade> templateFwUpgradeList = templateFwUpgradeMapper.selectList(Wrappers.<TemplateFwUpgrade>lambdaQuery()
                .in(TemplateFwUpgrade::getFwFileId, fileIdList));
        if (CollectionUtils.isEmpty(templateFwUpgradeList)) {
            log.warn("decode firmware upgrade result warning,templateFwUpgradeList is empty");
            return;
        }
        List<Long> templateIdList = templateFwUpgradeList.stream().map(TemplateFwUpgrade::getTemplateId).collect(Collectors.toList());
        List<LogFwUpgradeHis> logFwUpgradeHisList = logFwUpgradeHisMapper.selectList(Wrappers.<LogFwUpgradeHis>lambdaQuery()
                .in(LogFwUpgradeHis::getTemplateId, templateIdList)
                .eq(LogFwUpgradeHis::getDeviceType, DeviceType.METER.getId())
                .eq(LogFwUpgradeHis::getTaskType, com.smsc.headend.module.fwu.entity.TemplateFwUpgrade.TaskType.FtpSettings.getCode())
                .eq(LogFwUpgradeHis::getPushStatus, LogFwUpgradeHis.PushStatus.not_pushed.getCode())
        );
        int pushStatus;
        int upgradeResult;
        if (Status.success.getCode().equals(status)) {
            pushStatus = LogFwUpgradeHis.PushStatus.success.getCode();
            upgradeResult = LogFwUpgradeHis.UpgradeResult.success.getCode();
        } else {
            pushStatus = LogFwUpgradeHis.PushStatus.failed.getCode();
            upgradeResult = LogFwUpgradeHis.UpgradeResult.failed.getCode();
        }
        List<Meter> meters = assetManagementService.getMetersByDcuId(dcuId);
        List<Long> meterIds = meters.stream().map(Meter::getMeterId).collect(Collectors.toList());
        Long uploadDateTime = uploadDate.getTime() / 1000;
        Long readVersionTaskId = null;
        for (LogFwUpgradeHis logFwUpgradeHis : logFwUpgradeHisList) {
            if (!meterIds.contains(logFwUpgradeHis.getDeviceId())) {
                continue;
            }
            Long taskId = processLogFwUpgradeHis(logFwUpgradeHis, pushStatus, upgradeResult, uploadDateTime, DeviceType.METER.getId().intValue());
            if (null != taskId) {
                readVersionTaskId = taskId;
            }
        }
        if (null != readVersionTaskId) {
            assetManagementService.updateFwScheduleTaskLog(readVersionTaskId, uploadDateTime);
        }

    }


    private Long updateMeterFwUpgradeHisLog(Long meterId, String fileName, String fileType, Integer status, Integer deviceType, Date uploadDate, Long modelId) {
        Long templateId = configMeterTemplateMapper.getMeterTemplateId(meterId, "FWUPGRADE_TEMPLATE_ID");
        if (null == templateId) {
            return null;
        }
        return updateFwUpgradeHisLog(templateId, meterId, deviceType, uploadDate, status, fileName, fileType);
    }

    private Long updateDcuFwUpgradeHisLog(Long dcuId, String fileName, String fileType, Integer status, Integer deviceType, Date uploadDate, Long modelId) {
        Long templateId = configDcuTemplateMapper.getDcuTemplateId(dcuId, "FWUPGRADE_TEMPLATE_ID");
        if (null == templateId) {
            log.debug("decode firmware upgrade result error,device:{} did not config FWUPGRADE_TEMPLATE_ID:{}", dcuId, templateId);
            return null;
        }
        return updateFwUpgradeHisLog(templateId, dcuId, deviceType, uploadDate, status, fileName, fileType);
    }

    private Long updateFwUpgradeHisLog(Long templateId, Long deviceId, Integer deviceType, Date uploadDate, Integer status, String fileName, String fileType) {
        //查找固件更新模板
        TemplateFwUpgrade templateFwUpgrade = templateFwUpgradeMapper.selectById(templateId);
        if (null == templateFwUpgrade) {
            log.debug("decode firmware upgrade result error,templateFwUpgrade is null,deviceId:{}", deviceId);
            return null;
        }
        //查找固件文件信息
        FirmwareFile firmwareFile = firmwareFileMapper.selectById(templateFwUpgrade.getFwFileId());
        if (null == firmwareFile) {
            log.debug("decode firmware upgrade result error,firmwareFile is null,deviceId:{}", deviceId);
            return null;
        }
        String fileTypeDb = "";
        if (firmwareFile.getFwFileTypeId() == 11L) {
            fileTypeDb = "3";
            if (!fileTypeDb.equals(fileType)) {
                log.debug("decode firmware upgrade result error,firmwareFile is diff,fileTypeDb:{},fileType:{}", fileTypeDb, fileType);
                return null;
            }
        }
        if (!fileName.equals(firmwareFile.getFwFileName())) {
            log.debug("decode firmware upgrade result error,fileName is diff,fileNameDb:{},fileName:{}", fileTypeDb, fileName);
            return null;
        }
        Long fwTypeId = firmwareFileMapper.getFwTypeIdByFwFileTypeId(firmwareFile.getFwFileTypeId());
        //成功则写入版本
        if (Status.success.getCode().equals(status)) {
            FirmwareFileVersion firmwareFileVersion = firmwareFileVersionMapper.selectByFwFileIdAndFwTypeId(firmwareFile.getFwFileId(), fwTypeId);
            DeviceFirmwareVersion firmwareVersion = new DeviceFirmwareVersion();
            firmwareVersion.setFwVersion(firmwareFileVersion.getFwVersion());
            firmwareVersion.setFwType(fwTypeId);
            firmwareVersion.setDeviceId(deviceId);
            firmwareVersion.setDeviceType(deviceType.longValue());
            deviceFirmwareVersionService.saveFirmwareVersion(firmwareVersion);
        }
        List<LogFwUpgradeHis> hisList = logFwUpgradeHisMapper.selectList(Wrappers.<LogFwUpgradeHis>lambdaQuery()
                .eq(LogFwUpgradeHis::getTemplateId, templateId)
                .eq(LogFwUpgradeHis::getDeviceId, deviceId)
                .eq(LogFwUpgradeHis::getDeviceType, deviceType)
                .eq(LogFwUpgradeHis::getTaskType, com.smsc.headend.module.fwu.entity.TemplateFwUpgrade.TaskType.FtpSettings.getCode())
                .eq(LogFwUpgradeHis::getPushStatus, LogFwUpgradeHis.PushStatus.not_pushed.getCode()));
        if (CollectionUtils.isEmpty(hisList)) {
            return null;
        }
        List<LogFwUpgradeHis> hisListSort = hisList.stream().sorted(Comparator.comparing(LogFwUpgradeHis::getTvCreate).reversed()).collect(Collectors.toList());
        LogFwUpgradeHis newtest = hisListSort.get(0);
        int pushStatus;
        int upgradeResult;
        if (Status.success.getCode().equals(status)) {
            pushStatus = LogFwUpgradeHis.PushStatus.success.getCode();
            upgradeResult = LogFwUpgradeHis.UpgradeResult.success.getCode();
        } else {
            pushStatus = LogFwUpgradeHis.PushStatus.failed.getCode();
            upgradeResult = LogFwUpgradeHis.UpgradeResult.failed.getCode();
        }
        return processLogFwUpgradeHis(newtest, pushStatus, upgradeResult, uploadDate.getTime() / 1000, deviceType);
    }

    private Long processLogFwUpgradeHis(LogFwUpgradeHis logFwUpgradeHis, Integer pushStatus, Integer upgradeResult, Long uploadDateTime, Integer deviceType) {
        ConfigScheduleTask readVersionTask = taskMapper.selectOne(Wrappers.<ConfigScheduleTask>lambdaQuery().eq(ConfigScheduleTask::getTaskPid, logFwUpgradeHis.getTaskId()));
        if (null == readVersionTask) {
            //没有读版本的任务
            return null;
        }
        List<LogFwUpgradeHis> readVersionHisList = logFwUpgradeHisMapper.selectList(Wrappers.<LogFwUpgradeHis>lambdaQuery()
                .eq(LogFwUpgradeHis::getTemplateId, readVersionTask.getTemplateId())
                .eq(LogFwUpgradeHis::getDeviceId, logFwUpgradeHis.getDeviceId())
                .eq(LogFwUpgradeHis::getDeviceType, deviceType)
                .eq(LogFwUpgradeHis::getTaskType, com.smsc.headend.module.fwu.entity.TemplateFwUpgrade.TaskType.ImageVerify.getCode())
                .eq(LogFwUpgradeHis::getTaskId, readVersionTask.getTaskId()));
        if (!CollectionUtils.isEmpty(readVersionHisList)) {
            //已经读过版本了，不处理push result
            return null;
        }
        LogFwUpgradeHis readVersionHis = new LogFwUpgradeHis();
        readVersionHis.setUpgradeResult(upgradeResult);
        readVersionHis.setTvStart(logFwUpgradeHis.getTvEnd());
        readVersionHis.setTvEnd(uploadDateTime);
        readVersionHis.setDeviceId(logFwUpgradeHis.getDeviceId());
        readVersionHis.setTvUpdate(uploadDateTime);
        readVersionHis.setTaskId(readVersionTask.getTaskId());
        readVersionHis.setTaskType(com.smsc.headend.module.fwu.entity.TemplateFwUpgrade.TaskType.ImageVerify.getCode());
//        readVersionHis.setDescr("push result");
        readVersionHis.setDeviceType(logFwUpgradeHis.getDeviceType());
        readVersionHis.setTvCreate(uploadDateTime);
        readVersionHis.setTemplateId(readVersionTask.getTemplateId());
        logFwUpgradeHisMapper.insert(readVersionHis);

        logFwUpgradeHis.setPushStatus(pushStatus);
        logFwUpgradeHis.setTvUpdate(uploadDateTime);
        logFwUpgradeHisMapper.updateById(logFwUpgradeHis);
//        assetManagementService.updateFwScheduleTaskLog(logFwUpgradeHis.getTaskId(), uploadDateTime);
        assetManagementService.initFwScheduleTaskLog(readVersionHis.getTaskId(), logFwUpgradeHis.getTvEnd(),null);
        return readVersionTask.getTaskId();
    }


    public enum Status {

        success(0), failure(1);

        Status(Integer code) {
            this.code = code;
        }

        public Integer getCode() {
            return code;
        }

        private Integer code;
    }
}
